package com.huangfu.learning.javabase.java.pattern.create.singleton;

/**
 * Created with IntelliJ IDEA.
 * Author: huangfu.daohui
 * Date: 2018/7/30
 * Time: 18:55
 * Version: 1.0
 * Description:单例模式 四种
 * https://blog.csdn.net/carson_ho/article/details/52223097
 * 1、饿汉式单例模式
 * 2、懒汉式单例模式
 * 3.双重检查式单例模式
 * 4.类级内部类单例模式
 * 推荐使用饿汉式单例模式和类级内部类单例模式
 **/
public class SinglePattern {

    public static void main(String[] args) {
        System.out.println(InnerSingle.getInnerSingleInstence());
    }
}

/**
 * 饿汉式单例模式（可用）
 * 优点：线程安全，调用时反应速度快，在类加载的时候（因为是static修饰的）已经创建了该对象（唯一的）
 * 缺点：资源利用效率不高，可能该实例并不需要，但是在类加载的手被创建了。
 */
class HungrySingle {

    /**
     * 防止外部创建实例 私有
     * Singleton.
     */
    private HungrySingle() {

    }

    private static HungrySingle hungrySingleInstence = new HungrySingle();

    public static HungrySingle getInstence() {
        return hungrySingleInstence;
    }
}

/**
 * 懒汉模式单例 （不推荐用）
 * 优点：synchronized线程安全，资源利用率高,不执行getInstance就不会被实例。
 * 缺点：第一次加载时反应不快，多线程使用不必要的同步开销大
 */
class LazySingle {

    /**
     * 防止外部创建实例 私有
     * Singleton.
     */
    private LazySingle() {

    }

    private static LazySingle lazySingleInstence;

    public static synchronized LazySingle getLazySingleInstence() {
        if (lazySingleInstence == null) {
            lazySingleInstence = new LazySingle();
        }
        return lazySingleInstence;
    }
}

/**
 * 双重检查单例模式（推荐用）
 * 优点：资源利用率高，不执行getDclSingleInstence就不会被实例化，多线程效率高
 * 缺点：第一次加载时速度慢
 * <p>
 * 当instance为null时，两个线程可以并发地进入if语句内部。
 * 然后，一个线程进入synchronized块来初始化instance，而另一个线程则被阻断。
 * 当第一个线程退出synchronized块时，等待着的线程进入并创建另一个DCLSingle对象。
 * 注意：当第二个线程进入 synchronized 块时，它并没有检查 instance 是否非 null。
 * 因此我们需要对instance进行第二次非空检查，这也是“双重检查加锁”名称的由来。
 */
class DCLSingle {

    /**
     * 防止外部创建实例 私有
     * Singleton.
     */
    private DCLSingle() {

    }

    // volatile 内存可见性：通俗来说就是，线程A对一个volatile变量的修改，对于其它线程来说是可见的，即线程每次获取volatile变量的值都是最新的。
    private static volatile DCLSingle dclSingleInstence;

    public static DCLSingle getDclSingleInstence() {

        if (dclSingleInstence == null) {
            synchronized (DCLSingle.class) {
                if (dclSingleInstence == null) {
                    dclSingleInstence = new DCLSingle();
                }
            }
        }
        return dclSingleInstence;
    }
}

/**
 * 类级内部类单例模式（推荐用）
 * 相应的基础知识
 * （1）什么是类级内部类？
 * 简单点说，类级内部类指的是，有static修饰的成员内部类。如果没有static修饰的成员式内部类被称为对象级内部类。
 * （2）类级内部类相当于其外部类的static成分，它的对象与外部类对象间不存在依赖关系，因此 可以直接创建。而对象级内部类的实例，是绑定在外部对象实例中的。
 * （3）类级内部类中，可以定义静态的方法。在静态方法中只能引用外部类中的静态成员方法或变量。
 * （4）类级内部类相当于其外部类的成员，只有在第一次被使用的时候才会被装载。
 * <p>
 * 这样就满足了延时加载，而不会在类加载器加载其外部类的时候被装载，而且只会被加载一次。
 * 因此，资源利用率高。且线程安全；也克服了上面因为同步导致的效率低下的问题。
 */
class InnerSingle {

    /**
     * 防止外部创建实例 私有
     * Singleton.
     */
    private InnerSingle() {

    }

    private static class SingleHolder {
        public static InnerSingle innerSingle = new InnerSingle();
    }

    public static InnerSingle getInnerSingleInstence() {
        return SingleHolder.innerSingle;
    }
}